package com.yq.canalkafka.appender;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.yq.canalkafka.config.ApplicationContextProvider;
import com.yq.canalkafka.config.SysProperties;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Objects;

/**
 * @author by shizan
 * @Classname SendErrorMsgAppender
 * @Description TODO
 * @Date 2020/12/17 10:56 上午
 */

@Slf4j
public class SendErrorMsgAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {


    private HttpHeaders headers;

    public SendErrorMsgAppender() {
        headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    }

    @Override
    protected void append(ILoggingEvent event) {
        SysProperties sysProperties = ApplicationContextProvider.getBean(SysProperties.class);

        if (event.getLevel() == Level.ERROR) {
            //没有启用
            if (!sysProperties.getWaringDingdingEnable()) {
                return;
            }
            IThrowableProxy iThrowableProxy = event.getThrowableProxy();
            StringBuilder sb = new StringBuilder();
            if (iThrowableProxy != null && iThrowableProxy instanceof ThrowableProxy) {
                ThrowableProxy throwableProxy = (ThrowableProxy) iThrowableProxy;
                Throwable throwable = throwableProxy.getThrowable();
                String throwableMsg = throwable.getMessage();
                StackTraceElementProxy[] stackTraceElementProxy = iThrowableProxy.getStackTraceElementProxyArray();
                //获取服务器Ip，告知哪台服务器抛异常
                InetAddress addr = null;
                try {
                    addr = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    //不能打印error日志，否则会死循环
                }
                String active = sysProperties.getActive();
                if (Objects.nonNull(addr)) {
                    //获得本机IP
                    String ip = addr.getHostAddress();
                    //获得本机名称
                    String address = addr.getHostName();

                    if (!Strings.isNullOrEmpty(ip)) {
                        sb.append("服务器:").append(ip).append("\n");
                    }
                    if (!Strings.isNullOrEmpty(address)) {
                        sb.append("hostName:").append(address).append("\n");
                    }
                }
                sb.append("active:").append(active).append("\n");
                sb.append(event.getFormattedMessage()).append("\n");
                if (!Strings.isNullOrEmpty(throwableMsg)) {


                    sb.append(throwableMsg).append("\n");
                }
                int i = 0;
                for (StackTraceElementProxy proxy : stackTraceElementProxy) {
                    //只打印40行的堆栈
                    if (i < 40) {
                        sb.append(proxy.getSTEAsString()).append("\n");
                    } else {
                        break;
                    }
                    i++;
                }
            } else {
                sb.append(event.getFormattedMessage());
            }
            String msg = sb.toString();
            if (!Strings.isNullOrEmpty(msg)) {

                sendMsgToDingDing(msg, sysProperties);
            }
        }
    }

    /**
     * @param msg
     * @return
     */
    private Map<String, Object> sendMsgToDingDing(String msg, SysProperties sysProperties) {
        ObjectMapper objectMapper = ApplicationContextProvider.getBean(ObjectMapper.class);

        RestTemplate restTemplate = ApplicationContextProvider.getBean("restTemplate", RestTemplate.class);

        Text text = new Text();
        text.setContent(msg);
        DdMsgBody msgBody = DdMsgBody.builder().msgtype("text").text(text).build();
        String json = null;
        try {
            json = objectMapper.writeValueAsString(msgBody);
        } catch (Exception e) {
            //不记录日志，有可能死循环
            //log.error("error", e);
        }
        if (null == json) {
            return null;
        }
        HttpEntity<String> formEntity = new HttpEntity<>(json, headers);
        String url = sysProperties.getWaringDingdingFormatUrl();
        Long timestamp = System.currentTimeMillis();
        String sign = getSign(timestamp, sysProperties.getWaringDingdingSecret());
        url = url + "&timestamp=" + timestamp + "&sign=" + sign;
        Map<String, Object> result = restTemplate.postForObject(url, formEntity, Map.class);
        return result;
    }


    @Builder
    @Data
    private static class DdMsgBody {
        private String msgtype;
        private Text text;
    }

    @Data
    private class Text {
        private String content;
    }

    private String getSign(Long timestamp, String secret) {
        String stringToSign = timestamp + "\n" + secret;
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
            return sign;
        } catch (Exception e) {

        }

        return null;
    }
}
